package com.mntp;

import com.mntp.handler.server.ServerInboundHandler1;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import java.net.InetSocketAddress;

import lombok.extern.slf4j.Slf4j;

/**
 * netty服务端
 */
@Slf4j
public class NettyServer {

    public static void main(String[] args) {
        NettyServer server = new NettyServer();
        server.start(9999);
    }

    /**
     * 启动服务端
     *
     * @param port 端口号
     */
    private void start(int port) {
        // 基于reactor主从模型
        // 主备boss和worker线程池
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        // 准备服务端引导类，通过相关配置来引导启动服务端
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        // 配置相关参数
        serverBootstrap.group(bossGroup, workerGroup)
        // 配置服务端channel
        .channel(NioServerSocketChannel.class)
        // 配置服务端channel的handler,打印日志
        .handler(new LoggingHandler(LogLevel.INFO))
        // 给客户端channel添加handler
        .childHandler(new ChannelInitializer<SocketChannel>() {
            // 当客户端连接的时候会调用该方法,客户端channel初始化的时候执行
            @Override
            protected void initChannel(SocketChannel channel) throws Exception {
                ChannelPipeline pipeline = channel.pipeline();
                //maxFrameLength 设置为一个合理的上限，比如 1024 * 1024（1MB）或 10 * 1024 * 1024（10MB）。
                pipeline.addLast(new LengthFieldBasedFrameDecoder(1024 * 1024, 0, 4, 0, 4));
                pipeline.addLast(new ServerInboundHandler1());
            }
        });

        try {
            // 绑定端口并启动(netty内部都是异步执行的，这里绑定端口需要同步执行，手动设置同步)
            log.info("Binding server to port: " + port);
            ChannelFuture future = serverBootstrap.bind(new InetSocketAddress(port)).sync();
            log.info("Server started and listening on port: " + port);
            // 监听服务端端口的关闭，做一些优雅释放资源操作
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("服务端异常了。。。。Server startup interrupted", e);
            throw new RuntimeException(e);
        } finally {
            // 优雅的关闭
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            log.info("Shutting down boss and worker groups");
        }
    }
}
